package se581.banker;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import se581.banker.BankerConstants.TrackerEventGroup;
import se581.banker.client.QueryClient;
import se581.banker.client.UpdateClient;
import se581.banker.event.EventFactory;
import se581.banker.event.TrackerEvent;
import se581.banker.proxy.InquiryProxy;
import se581.banker.proxy.UpdateProxy;
import se581.banker.service.RegistrationService;
import se581.banker.util.EventFileReader;

/**
 * This is a simulation object that takes the input file events and hands
 * them to their respective update or query client to run through the system.
 * 
 * @author mmichalak
 *
 */
public class SimulationEventProxy {
	static Logger logger = Logger.getLogger(SimulationEventProxy.class.getName());
	

	/**
	 * Maps hold the client threads. Each thread gets 
	 */
	Map<String, UpdateClient> updateClients = null;
	Map<String, QueryClient> inquryClients = null;
	
	/*
	 * TEMP for sim to create/assign clients port nums
	 * The port nums are actually not used at this time.
	 * Held by Reg Svc */
	int simUpClientPortNumCounter = 9001;
	int simInqClientPortNumCounter = 10002; 
	
	RegistrationService regSvc = null;
	
	
	/**
	 * This is the step that starts the simulation in motion
	 */
	public void readEvents() {
		// 1. Read file
		EventFileReader er = new EventFileReader();
		List<String> lines = er.readFile();
		
		// 2. For Each line, convert to event w/ Factory
		int eventNo = 0;
		int currTick = 0;  // Used to send groups of events by ticks
		for (String line : lines) {
			eventNo++;

			TrackerEvent ev = EventFactory.createEvent(line);
			ev.setSystemId(eventNo);
			int tick = ev.getTick();

			// Sleep Loop to pace events like clock ticks
			 try {
			        if (currTick != tick) {
			            Thread.sleep(BankerConstants.TICK_LENGTH);
			            currTick = tick;
			        }
			 } catch (InterruptedException e) {
			        e.printStackTrace();
			 }
				
			// 3. Determine event type and hand to approp client (or a failover event to Registration Service)
			if (ev.getEventGroup() == TrackerEventGroup.UPDATE) {
				UpdateClient updateClient = getUpdateClient(ev.getId());
				updateClient.addEvent(ev);
			}
			else if (ev.getEventGroup() == TrackerEventGroup.QUERY) {
				QueryClient inquiryClient = getInquiryClient(ev.getId());
				inquiryClient.addEvent(ev);
			}
			else if (ev.getEventGroup() == TrackerEventGroup.BLANK) {
				; // DO NOTHING.  This is an empty clock tick
			}

			logger.debug("Event No=" + eventNo + " Tick=" + tick + "   " + ev.getEventType() + "  Id=" + ev.getId());
		}

	}


	/**
	 * Manages the collection of QueryClients
	 * @param id = key
	 * @return
	 */
	UpdateClient getUpdateClient(String id) {
		UpdateClient client = updateClients.get(id);
		if (client == null) {
			client = new UpdateClient();
			client.setProxy( new UpdateProxy("localhost", Integer.toString(simUpClientPortNumCounter++)) );
			updateClients.put(id, client);
			
			Thread thr = new Thread(client);
	        thr.setDaemon(true);
	        thr.start();
		}
		
		return client;
	}
	
	
	QueryClient getInquiryClient(String id) {
		QueryClient client = inquryClients.get(id);
		if (client == null) {
			client = new QueryClient();
			client.setProxy( new InquiryProxy("localhost", Integer.toString(simInqClientPortNumCounter++)) );
			inquryClients.put(id, client);
			
			Thread thr = new Thread(client);
	        thr.setDaemon(true);
	        thr.start();
		}
		
		return client;	
	}
		
	
	public RegistrationService getRegSvc() {
		return regSvc;
	}


	public void setRegSvc(RegistrationService regSvc) {
		this.regSvc = regSvc;
	}


	public Map<String, UpdateClient> getUpdateClients() {
		return updateClients;
	}


	public void setUpdateClients(Map<String, UpdateClient> updateClients) {
		this.updateClients = updateClients;
	}

	public void setInquryClients(Map<String, QueryClient> inquryClients) {
		this.inquryClients = inquryClients;
	}

}
